package com.theaf.basemodule.service.impl;

import com.theaf.basemodule.common.api.DataExService;
import com.theaf.basemodule.common.dto.dataEx.DataDefDTO;
import com.theaf.basemodule.common.model.SysDataEx;
import com.theaf.basemodule.common.model.SysDataExDef;
import com.theaf.basemodule.common.model.SysExGroup;
import com.theaf.basemodule.dao.SysDataExDAO;
import com.theaf.basemodule.dao.SysDataExDefDAO;
import com.theaf.basemodule.dao.SysExGroupDAO;
import com.theaf.basemodule.service.constants.StateConstant;
import com.theaf.core.constant.SymbolConstant;
import com.theaf.core.repo.kit.SimpleSortBuilder;
import com.theaf.core.repo.specification.SqlBuilder;
import com.theaf.core.repo.specification.SqlOperator;
import com.theaf.core.repo.specification.SqlValue;
import com.theaf.core.repo.specification.SubqueryEx;
import com.theaf.core.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author:songwenke
 * @Description:数据扩展服务实现
 * @Date:create in 10:41 2018/3/16
 * @Modified By:
 **/
@Service
public class DataExServiceImpl implements DataExService{
    @Autowired
    private SysDataExDAO sysDataExDAO;
    @Autowired
    private SysDataExDefDAO sysDataExDefDAO;
    @Autowired
    private SysExGroupDAO sysExGroupDAO;

    /**
     * 判断数据是否引用
     * @param groupNo
     * @return
     */
    @Override
    public boolean judgeRef(Long groupNo){
        if(groupNo==null)
            return false;
        return sysExGroupDAO.count(SqlBuilder.start("parentPath",
                SqlOperator.OPER.LIKES,SqlValue.parse(groupNo.toString())).gen())>0;
    }

    /**
     * 查询对象的属性定义
     * @param obj 使用对象，支持,分割
     * @param fieldPath 属性路径,为空表示主属性列表
     * @return
     */
    @Override
    public List<DataDefDTO> getAttrs(String obj,String fieldPath) {
        SqlBuilder builder = SqlBuilder.start("obj",SqlOperator.OPER.LIKES,SqlValue.parse(obj));
        if(fieldPath==null){
            builder = builder.and("pid", SqlOperator.OPER.NULL,null);
        }else{
            SubqueryEx subqueryEx = sysDataExDefDAO.subquery(
                    SqlBuilder.start("obj",SqlOperator.OPER.LIKES,SqlValue.parse(obj))
                            .and("fieldPath",fieldPath).and("id","@parent.id"));
            builder = builder.and(subqueryEx, SqlOperator.OPER.EXISTS,null);
        }
        List<SysDataExDef> defs = sysDataExDefDAO.query(builder.gen());
        if(defs.size()==0){
            defs = sysDataExDefDAO.findAll(
                    SqlBuilder.start(SqlValue.parse(obj), SqlOperator.OPER.LIKER,"obj")
                            .and("fieldPath",fieldPath).gen(),
                    SimpleSortBuilder.generateSort("orderNo"));
        }
        return defs.parallelStream().map(
                n-> BeanMapper.map(n,DataDefDTO.class)).collect(Collectors.toList());
    }

    /**
     * 查询对象下扩展主属性及直接子属性，不包括相对子属性
     * @param obj 匹配方式相等
     * @return 按对象类型的属性名称分组的属性集合
     */
    @Override
    public Map<String, List<DataDefDTO>> getAttrMap(String obj) {
        List<SysDataExDef> defs = sysDataExDefDAO.findAll(
                SqlBuilder.start("obj",SqlOperator.OPER.LIKES,SqlValue.parse(obj)).gen());
        Map<String, List<DataDefDTO>> rets = new HashMap();
        rets.put("基本属性",new ArrayList());
        for(SysDataExDef def:defs){
            if(def.getParent()==null){
                rets.get("基本属性").add(BeanMapper.map(def,DataDefDTO.class));
            }else{
                List<DataDefDTO> dtos = rets.get(def.getParent().getFieldTip());
                if(dtos==null){
                    dtos = new ArrayList<>();
                    rets.put(def.getParent().getFieldTip(),dtos);
                }
                dtos.add(BeanMapper.map(def,DataDefDTO.class));
            }
        }
        return rets;
    }

    /**
     * 获取业务的扩展条件
     * @param jsonTerm 条件
     * @param ref 与业务的关系
     * @return 子查询条件
     */
    @Override
    public List<SubqueryEx> getExTerm(String jsonTerm, String ref) {
        Map term = JsonUtil.parseObject(jsonTerm,HashMap.class);
        List<SubqueryEx> subqueryExes =  new ArrayList<>();
        for(Object key:term.keySet()){
            SqlBuilder sqlBuilder = SqlBuilder.start("def.id",key);
            Object value = term.get(key);
            this.makeTerm(sqlBuilder,value);
            sqlBuilder.and("group.parentPath", SqlOperator.OPER.LIKES,ref);
            subqueryExes.add(sysDataExDAO.subquery(sqlBuilder));
        }
        return subqueryExes;
    }

    /**
     * 生成条件
     * @param sqlBuilder
     * @param value
     */
    private void makeTerm(SqlBuilder sqlBuilder,Object value){
        if(value instanceof String){
            sqlBuilder.and("fieldValue", SqlOperator.OPER.LIKE,value);
        }else if(value instanceof List){

        }
    }

    /**
     * 行列数据转换
     * @param datas
     * @return
     */
    private List<Map> dataExToMaps(List<SysDataEx> datas){
        Map<Long,Map> rets = new LinkedHashMap();
        for(SysDataEx data:datas){
            SysDataExDef def = data.getDef();
            SysExGroup group = data.getGroup();
            if(group==null||def==null){
                continue;
            }
            Map item = rets.get(data.getGroup().getId());
            if(item==null){
                item = new HashMap();
                item.put("id@",group.getId());
                SysExGroup parentSysExGroup = group.getParent();
                if(parentSysExGroup!=null){
                    item.put("parentId@", parentSysExGroup.getId());
                    if(def.getParent()==null){
                        throw SmExceptionHelper.reqAuthFailedException("存在数据异常");
                    }
                    item.put("parent@name", def.getParent().getFieldName());
                }
                rets.put(data.getGroup().getId(),item);
            }
            item.put(data.getFieldName(),data.getFieldValue());
            if(StringUtils.isNotEmpty(data.getFieldTitle())){
                item.put(data.getFieldName()+"$title",data.getFieldTitle());
            }
            if(StringUtils.isNotEmpty(data.getLevelCode())) {
                item.put(data.getFieldName() + "$levelcode", data.getLevelCode());
            }
        }
        return rets.values().stream().collect(Collectors.toList());
    }

    /**
     * 查询子对象数据
     * @param parentGroupNo 父组ID
     * @param fieldName  对象属性名
     * @param term 其它条件
     * @return
     */
    @Override
    public List<Map> findSubData(Long parentGroupNo,String fieldName,Map<String,String> term) {
        SqlBuilder sqlBuilder = SqlBuilder.start("group.parent.id",parentGroupNo);
        if(StringUtils.isNotEmpty(fieldName)){
            sqlBuilder.and(sysDataExDefDAO.subquery(SqlBuilder.start("parent.fieldName",SqlValue.parse(fieldName))
                            .and("id","@def.id")),
                    SqlOperator.OPER.EXISTS,null);
        }
        if(term!=null)
        for(Object key:term.keySet()){
            sqlBuilder.and(sysDataExDAO.subquery(SqlBuilder.start("fieldName",SqlValue.parse(key))
                            .and("fieldValue", SqlOperator.OPER.LIKE,SqlValue.parse(term.get(key)))
                            .and("groupNo","@groupNo")),
                    SqlOperator.OPER.EXISTS,null);
        }
        return dataExToMaps(sysDataExDAO.findAll(sqlBuilder.gen(),
                SimpleSortBuilder.generateSort("group.orderNo")));
    }
    /**
     * 查询子数据
     * @param groupNo 组号
     * @return
     */
    @Override
    public List<Map> find(Long groupNo) {
        return dataExToMaps(sysDataExDAO.findAll(SqlBuilder.start("group.id",groupNo).gen(),
                SimpleSortBuilder.generateSort("group.orderNo")));
    }

    /**
     * 查询嵌套子数据，JSON结构
     * @param groupNo
     * @return
     */
    public String findJson(Long groupNo){
        List<Map> maps = dataExToMaps(sysDataExDAO.findAll(
                SqlBuilder.start("group.ppath", SqlOperator.OPER.LIKES,groupNo)
                        .or("group.id",groupNo).gen(),
                SimpleSortBuilder.generateSort("group.orderNo")));
        //形成对象结构
        Map<Long,List> subs = new HashMap();//存储子对象
        Map<Long,Map> vmap = new HashMap();//ID对象映射
        Map<Long,String> nameMap = new HashMap();//集合名称映射
        //按父对象分组
        for(Map map:maps){
            Long pid = (Long)map.get("parentId@");
            Long id = (Long)map.get("id@");
            String pname = (String)map.get("parent@name");
            nameMap.put(pid,pname);
            vmap.put(id,map);
            List vs = subs.get(pid);
            if(vs==null) {
                vs = new ArrayList();
                subs.put(pid,vs);
            }
            vs.add(map);
        }
        //再把集合加到对应的对象中
        for(Long key:vmap.keySet()){
            String fieldName = nameMap.get(key);
            vmap.get(key).put(fieldName,subs.get(key));
        }
        return JsonUtil.toJSONString(vmap.get(groupNo));
    }

    /**
     * 查询父对象数据
     * @param fieldToValueMap 自定义条件,
     * @param fieldName 结果属性名，如果为空表示主对象
     * @return
     */
    @Override
    public List<Map> findParent(Map fieldToValueMap,String fieldName){
        SqlBuilder sqlBuilder = null;
        if(StringUtils.isNotEmpty(fieldName)){
            sqlBuilder = SqlBuilder.start(sysDataExDefDAO.subquery(
                    SqlBuilder.start("parent.fieldName",SqlValue.parse(fieldName))
                            .and("id","@def.id")),
                    SqlOperator.OPER.EXISTS,null);
        }else{
            sqlBuilder = SqlBuilder.start(sysDataExDefDAO.subquery(
                    SqlBuilder.start("parent", SqlOperator.OPER.NULL,null)
                            .and("id","@def.id")),
                    SqlOperator.OPER.EXISTS,null);
        }
        if(fieldToValueMap!=null) {
            for (Object key : fieldToValueMap.keySet()) {
                sqlBuilder.and(sysDataExDAO.subquery(SqlBuilder.start("fieldName", SqlValue.parse(key))
                                .and("fieldValue", SqlValue.parse(fieldToValueMap.get(key)))
                                .and("group.parentPath", SqlOperator.OPER.LIKES,
                                        "@group.id")),
                        SqlOperator.OPER.EXISTS, null);
            }
        }else
            throw SmExceptionHelper.reqAuthFailedException("fieldToValueMap必须设置");
        return dataExToMaps(sysDataExDAO.query(sqlBuilder.gen()));
    }


    /**
     * 保存数据
     * @param json 注意名称是属性ID，不是属性名称
     * @param  obj 所属对象
     */
    @Override
    public void saveData(String json,String obj) {
        List<SysDataExDef> defs = sysDataExDefDAO.findAll(SqlBuilder.start("obj",
                SqlOperator.OPER.LIKES,SqlValue.parse(obj)).gen());
        Map<Long,SysDataExDef> defMap = new HashMap();
        for(SysDataExDef def:defs){
            defMap.put(def.getId(),def);
        }
        if(json.startsWith("[")){
            List datas = JsonUtil.parseArray(json,HashMap[].class);
            int i=1;
            for(Object data:datas){
                this.saveMap(i++,(Map)data,defMap);
            }
        }else{
            Map data = JsonUtil.parseObject(json,HashMap.class);
            this.saveMap(1,data,defMap);
        }
    }

    private void saveMap(int orderNo,Map map,Map<Long,SysDataExDef> defMap){
        Long groupNo = null;
        Long parentGroupNo = null;
        String parentPath = null;
        Object id_ = map.get("id@");
        Object pid_ = map.get("parentId@");
        List<SysDataEx> sysDataExs = null;
        SysExGroup group = null;
        if(id_!=null){
            groupNo = ((Number)id_).longValue();
            group = sysExGroupDAO.findOne(SqlBuilder.start("id",groupNo).gen());
        }
        if(pid_!=null){
            parentGroupNo = ((Number)pid_).longValue();
            SysExGroup parentSysExGroup = sysExGroupDAO.findOne(SqlBuilder.start("id",parentGroupNo).gen());
            parentPath = (parentSysExGroup.getParentPath()==null?SymbolConstant.COMMA:parentSysExGroup.getParentPath())
                    +parentGroupNo+SymbolConstant.COMMA;
        }
        if (group == null) {
            group = new SysExGroup();
            group.setId(groupNo != null ? groupNo : sysExGroupDAO.getNextReq());
            group.setState(StateConstant.ADD);
            group.setOrderNo(orderNo);
            if(parentGroupNo!=null) {
                group.setParent(new SysExGroup(parentGroupNo));
                group.setParentPath(parentPath);
            }
            sysExGroupDAO.save(group);
        }else{
            group.setState(StateConstant.UPDATE);
            sysExGroupDAO.save(group);
        }
        for(Object key:map.keySet()){
            SysDataEx sysDataEx = null;
            Object value = map.get(key);
            if(value==null) continue;
            if(value instanceof List){
                int i=1;
                for(Map sub:(List<Map>)value){
                    sub.put("parentId@",group.getId());
                    this.saveMap(i++,sub,defMap);
                }
            }else if(value instanceof Map){
                ((Map)value).put("parentId@",group.getId());
                this.saveMap(1,(Map)value,defMap);
            }else {
                long fieldId = Long.parseLong((String) key);//字段ID
                for (SysDataEx data : sysDataExs) {
                    if (data.getDef().getId() == fieldId) {
                        sysDataEx = data;
                        break;
                    }
                }
                SysDataExDef sysDataExDef = defMap.get(fieldId);
                if (sysDataEx == null) {
                    sysDataEx = new SysDataEx();
                    sysDataEx.setGroup(group);
                    sysDataEx.setDef(sysDataExDef);
                }
                if (sysDataExDef != null) {
                    sysDataEx.setFieldName(sysDataExDef.getFieldName());
                    sysDataEx.setFieldValue(value.toString());
                    if(sysDataExDef.getFieldType()==DataDefDTO.TYPE_DIC){
                        String dicTitle = null;
                        for(String dicKey:value.toString().split(SymbolConstant.COMMA)) {
                            String temp = DictionaryHelper.getChlidValue(
                                    sysDataExDef.getFieldFormat().split(SymbolConstant.COLON)[0], dicKey);
                            if(dicTitle==null)
                                dicTitle = temp;
                            else
                                dicTitle += SymbolConstant.COMMA+temp;
                        }
                        sysDataEx.setFieldTitle(dicTitle);
                    }
                }else
                    throw SmExceptionHelper.reqAuthFailedException("字段"+fieldId+"未定义或未关联!");
                sysDataExDAO.save(sysDataEx);
            }
        }
    }

    /**
     * 删除数据
     * @param groupNo 组号
     */
    @Override
    public void deleteData(Long groupNo){
        sysDataExDAO.deleteCustom(SqlBuilder.start("group.parentPath",
                SqlOperator.OPER.LIKES,SqlValue.parse(groupNo.toString())));// 删除关联数据
        sysDataExDAO.deleteCustom(SqlBuilder.start("group.id",groupNo));//删除关联组号
        sysExGroupDAO.deleteCustom(SqlBuilder.start("parentPath",
                SqlOperator.OPER.LIKES,SqlValue.parse(groupNo.toString())));//删除自身数据
        sysExGroupDAO.deleteCustom(SqlBuilder.start("id",groupNo));//删除自身组号
    }

    public static void main(String[] args){
        String json = "[{\"23\":12345667663353453345351245654," +
                "\"b\":[{\"b\":\"sfd\",\"id@\":[1,2,4]},{\"b\":\"sfdsf\",\"c\":24}]," +
                "\"c\":{\"d\":\"sfdsf\",\"c\":234}" +
                "}]";
        Object o = JsonUtil.parseArray(json,HashMap[].class);
        System.out.println(o);
    }
}